#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
简化编译脚本：使用 distutils 编译 CTP API Python 扩展
不依赖 pybind11，直接使用标准库
集成了自动打包和安装功能
"""

import os
import sys
import platform
import shutil
import argparse
from pathlib import Path
from distutils.core import setup, Extension
from distutils.command.build_ext import build_ext as _build_ext

class CustomBuildExt(_build_ext):
    """自定义编译扩展类"""
    
    def build_extensions(self):
        # 设置编译器选项
        if self.compiler.compiler_type == 'msvc':
            # MSVC 编译器选项
            for ext in self.extensions:
                ext.extra_compile_args = [
                    '/bigobj',  # 处理大对象文件
                    '/std:c++11',  # C++11 标准
                    '/source-charset:gbk',  # 源文件字符集
                    '/execution-charset:gbk',  # 执行字符集
                    '/W4',  # 警告等级（与CMake保持一致）
                    '/EHsc'  # 异常处理
                ]
                # Windows 下不需要 rpath
        elif self.compiler.compiler_type == 'mingw64':
            # MinGW 编译器选项
            for ext in self.extensions:
                ext.extra_compile_args = [
                    '-std=c++11',  # C++11 标准（与MSVC保持一致）
                    '-O2',  # 优化等级
                    '-Wall',  # 警告等级（与MSVC /W4对应）
                    '-finput-charset=gbk',  # 输入字符集
                    '-fexec-charset=gbk'  # 执行字符集
                ]
        elif self.compiler.compiler_type == 'unix':
            # Unix/Linux/macOS 编译器选项
            for ext in self.extensions:
                ext.extra_compile_args = [
                    '-std=c++11',
                    '-O2',
                    '-Wall',
                    '-fPIC'
                ]
                # 运行时库搜索路径：确保扩展能在包目录内找到 .so 依赖
                if sys.platform == 'darwin':
                    # macOS 使用 @loader_path（等效于 $ORIGIN）
                    ext.extra_link_args = ['-Wl,-rpath,@loader_path']
                else:
                    # Linux 使用 $ORIGIN
                    ext.extra_link_args = ['-Wl,-rpath,$ORIGIN']
        
        # 调用父类方法
        _build_ext.build_extensions(self)

def get_current_dir():
    """获取当前脚本所在目录"""
    return os.path.dirname(os.path.abspath(__file__))

def read_depend_file():
    """读取.depend文件中的依赖列表和项目类型"""
    current_dir = get_current_dir()
    depend_file = os.path.join(current_dir, '.depend')
    
    project_type = "ctp"  # 默认项目类型
    files = []
    
    if not os.path.exists(depend_file):
        print("警告：未找到.depend文件，使用默认依赖列表")
        return project_type, [
            'thostmduserapi_wrap.cxx',
            'thostmduserapi_wrap.h', 
            'thosttraderapi_wrap.cxx',
            'thosttraderapi_wrap.h',
            'thostmduserapi_se.dll',
            'thostmduserapi_se.lib',
            'thosttraderapi_se.dll', 
            'thosttraderapi_se.lib'
        ]
    
    try:
        with open(depend_file, 'r', encoding='utf-8') as f:
            lines = f.readlines()
        
        # 读取项目类型和文件列表
        in_existing_section = False
        
        for line in lines:
            line = line.strip()
            if not line or line.startswith('#'):
                if "实际存在的文件" in line:
                    in_existing_section = True
                continue
            
            # 读取项目类型
            if line.startswith('PROJECT_TYPE='):
                project_type = line.split('=', 1)[1].strip()
                continue
            
            if in_existing_section and line and not line.startswith('#'):
                files.append(line)
        
        # 如果没有找到文件，使用默认列表
        if not files:
            files = [
                'thostmduserapi_wrap.cxx',
                'thostmduserapi_wrap.h', 
                'thosttraderapi_wrap.cxx',
                'thosttraderapi_wrap.h',
                'thostmduserapi_se.dll',
                'thostmduserapi_se.lib',
                'thosttraderapi_se.dll', 
                'thosttraderapi_se.lib'
            ]
        
        return project_type, files
        
    except Exception as e:
        print(f"读取.depend文件失败: {e}，使用默认依赖列表")
        return project_type, [
            'thostmduserapi_wrap.cxx',
            'thostmduserapi_wrap.h', 
            'thosttraderapi_wrap.cxx',
            'thosttraderapi_wrap.h',
            'thostmduserapi_se.dll',
            'thostmduserapi_se.lib',
            'thosttraderapi_se.dll', 
            'thosttraderapi_se.lib'
        ]

def check_files():
    """检查必要文件是否存在"""
    current_dir = get_current_dir()
    
    # 从.depend文件读取项目类型和依赖列表
    project_type, required_files = read_depend_file()
    
    missing_files = []
    for file in required_files:
        if not os.path.exists(os.path.join(current_dir, file)):
            missing_files.append(file)
    
    if len(missing_files) > 0:
        print(f"错误：缺少必要文件: {', '.join(missing_files)}")
        return False
    return True

def copy_compiled_files(target_dir):
    """将编译好的文件拷贝到指定目录的 py[项目名] 子目录下
    
    Args:
        target_dir (str): 目标目录路径，相对于项目根目录
        
    此函数会从当前目录和 build 目录中找到所有编译文件，并将它们复制到 target_dir/py[项目名] 目录。
    后续会将 py[项目名] 目录安装到 site-packages。
    """
    
    # 获取项目类型
    project_type, _ = read_depend_file()
    
    # 构建目标路径
    target_path = target_dir
    if not target_path.exists():
        print(f"❌ 目标目录不存在: {target_path}")
        return False
    
    # 直接使用目标目录作为包目录
    package_dir = target_path
    package_dir.mkdir(exist_ok=True)
    
    copied_files = []
    
    # 1. 从当前目录查找已编译的扩展模块（Windows: .pyd，Linux/macOS: .so）
    current_dir = Path(".")
    compiled_files_found = []
    
    if current_dir.exists():
        # 查找当前目录中的扩展文件
        patterns = ["*.pyd", "*.so"]
        for pattern in patterns:
            compiled_files_found.extend(list(current_dir.glob(pattern)))
        if not compiled_files_found:
            print(f"⚠️  在当前目录中未找到已编译的扩展文件(.pyd/.so)")
    else:
        print(f"⚠️  当前目录不存在: {current_dir}")
    
    if compiled_files_found:
        for compiled_file in compiled_files_found:
            # 复制到目标目录
            dst = package_dir / compiled_file.name
            shutil.copy2(compiled_file, dst)
            copied_files.append(compiled_file.name)
            print(f"✅ 已复制 {compiled_file.name} 到 {package_dir}")
    else:
        print(f"⚠️  未找到任何扩展文件(.pyd/.so)")
    
    # 2. 从当前目录复制 .py 文件
    py_files = ["thosttraderapi.py", "thostmduserapi.py"]
    for py_file in py_files:
        src = Path(py_file)
        if src.exists():
            dst = package_dir / py_file
            shutil.copy2(src, dst)
            copied_files.append(py_file)
            print(f"✅ 已复制 {py_file} 到 {package_dir}")
        else:
            print(f"⚠️  未找到 {py_file}")
    
    # 3. 从当前目录复制运行时库（Windows: .dll，Linux/macOS: .so）
    # 读取.depend文件获取实际存在的库文件
    depend_libs = []
    depend_file = Path(".depend")
    if depend_file.exists():
        with open(depend_file, 'r', encoding='utf-8') as f:
            for line in f:
                line = line.strip()
                if line and not line.startswith('#'):
                    if line.endswith('.dll') or line.endswith('.so'):
                        lib_name = line
                        if Path(lib_name).exists():
                            depend_libs.append(lib_name)
    
    # 如果没有从.depend文件找到，使用默认的库文件列表（按平台）
    if not depend_libs:
        if sys.platform == 'win32':
            possible_libs = [
                "thostmduserapi_se.dll", "thosttraderapi_se.dll",
                "thostmduserapi.dll", "thosttraderapi.dll"
            ]
        else:
            # 同时尝试是否带 lib 前缀
            possible_libs = [
                "thostmduserapi_se.so", "thosttraderapi_se.so",
                "libthostmduserapi_se.so", "libthosttraderapi_se.so",
                "thostmduserapi.so", "thosttraderapi.so",
                "libthostmduserapi.so", "libthosttraderapi.so"
            ]
        depend_libs = [lib for lib in possible_libs if Path(lib).exists()]
    
    if depend_libs:
        for lib_file in depend_libs:
            src = Path(lib_file)
            dst = package_dir / lib_file
            shutil.copy2(src, dst)
            copied_files.append(lib_file)
            print(f"✅ 已复制 {lib_file} 到 {package_dir}")
    else:
        print(f"⚠️  未找到任何运行时库(.dll/.so)")
    
    # 4. 创建 __init__.py 文件
    project_type, _ = read_depend_file()
    package_name = f"py{project_type}"
    init_content = f"""# {package_name} package
# CTP API Python接口

import os
import sys
from pathlib import Path

# 获取 {package_name} 包的安装路径
_package_dir = Path(__file__).parent

# 在不同平台上设置运行库搜索路径，以避免导入失败
if sys.platform == 'win32':
    # Windows：优先使用 add_dll_directory，其次回退到 PATH
    if hasattr(os, 'add_dll_directory'):  # Python 3.8+
        try:
            os.add_dll_directory(str(_package_dir))
        except (OSError, AttributeError):
            os.environ['PATH'] = str(_package_dir) + os.pathsep + os.environ.get('PATH', '')
    else:  # Python 3.7 及以下
        os.environ['PATH'] = str(_package_dir) + os.pathsep + os.environ.get('PATH', '')
elif sys.platform.startswith('linux'):
    # Linux：在导入扩展前注入包目录到 LD_LIBRARY_PATH
    os.environ['LD_LIBRARY_PATH'] = str(_package_dir) + os.pathsep + os.environ.get('LD_LIBRARY_PATH', '')
elif sys.platform == 'darwin':
    # macOS：在导入扩展前注入包目录到 DYLD_LIBRARY_PATH（受SIP影响，优先依赖 rpath）
    os.environ['DYLD_LIBRARY_PATH'] = str(_package_dir) + os.pathsep + os.environ.get('DYLD_LIBRARY_PATH', '')

# 导入模块
from .thosttraderapi import *
from .thostmduserapi import *

__all__ = ['thosttraderapi', 'thostmduserapi']
"""
    init_file = package_dir / "__init__.py"
    init_file.write_text(init_content, encoding="utf-8")
    copied_files.append("__init__.py")
    print(f"✅ 已创建 {init_file}")
    
    # 检查复制结果
    if not copied_files:
        print("❌ 未复制任何文件")
        return False
    
    print(f"\n✅ 总共复制了 {len(copied_files)} 个文件到 {target_dir}:")
    for file in copied_files:
        print(f"  - {file}")
    
    return True

def create_pyctp_package(pyctp_dir):
    """将 pyctp 目录安装到 site-packages
    
    Args:
        pyctp_dir (Path): pyctp 目录的路径
    """
    try:
        # 获取用户级site-packages目录
        import site
        user_site = site.getusersitepackages()
        
        # 确保用户级site-packages目录存在
        os.makedirs(user_site, exist_ok=True)
        
        # 目标pyctp目录
        target_pyctp = Path(user_site) / "pyctp"
        
        # 如果目标目录已存在，先删除
        if target_pyctp.exists():
            shutil.rmtree(target_pyctp)
            print(f"✅ 已删除旧的pyctp目录: {target_pyctp}")
        
        # 复制pyctp目录到site-packages
        shutil.copytree(pyctp_dir, target_pyctp)
        print(f"✅ 已将pyctp目录复制到: {target_pyctp}")
        
        # 列出复制的文件
        copied_files = []
        for file in target_pyctp.glob("*"):
            if file.is_file():
                copied_files.append(file.name)
        
        print(f"\n✅ 总共复制了 {len(copied_files)} 个文件到 site-packages:")
        for file in copied_files:
            print(f"  - {file}")
        
        return True
        
    except Exception as e:
        print(f"❌ 创建pyctp包失败: {e}")
        return False

def verify_installation():
    """验证安装是否成功"""
    try:
        # 测试导入pyctp包
        import pyctp
        print("✅ pyctp包导入成功！")
        
        # 测试直接导入模块（避免循环导入）
        try:
            from pyctp import thosttraderapi
            print("✅ thosttraderapi模块导入成功！")
        except ImportError as e:
            print(f"⚠️  thosttraderapi导入警告: {e}")
            # 尝试直接导入底层模块
            from pyctp import _thosttraderapi
            print("✅ _thosttraderapi模块导入成功！")
        
        try:
            from pyctp import thostmduserapi
            print("✅ thostmduserapi模块导入成功！")
        except ImportError as e:
            print(f"⚠️  thostmduserapi导入警告: {e}")
            # 尝试直接导入底层模块
            from pyctp import _thostmduserapi
            print("✅ _thostmduserapi模块导入成功！")
        
        # 获取安装路径
        import site
        site_packages = Path(site.getusersitepackages())
        pyctp_dir = site_packages / "pyctp"
        
        if pyctp_dir.exists():
            print(f"✅ pyctp目录已安装: {pyctp_dir}")
            print("✅ 包含文件:")
            for file in pyctp_dir.glob("*"):
                if file.is_file():
                    print(f"  - {file.name} ({file.stat().st_size:,} bytes)")
        
        return True
        
    except ImportError as e:
        print(f"❌ 导入失败: {e}")
        print("提示：请确保所有.pyd文件已正确复制到pyctp目录")
        return False
    except Exception as e:
        print(f"❌ 验证过程出错: {e}")
        return False
    

def get_libraries_from_depend():
    """从.depend文件中获取库文件信息"""
    current_dir = get_current_dir()
    depend_file = os.path.join(current_dir, '.depend')
    
    libraries = {
        'md': 'thostmduserapi_se',
        'td': 'thosttraderapi_se'
    }
    
    if not os.path.exists(depend_file):
        print("警告：未找到.depend文件，使用默认库文件名")
        return libraries
    
    try:
        with open(depend_file, 'r', encoding='utf-8') as f:
            content = f.read()
        
        print(f"从.depend文件读取内容长度: {len(content)}")
        
        # 从依赖文件中提取库文件名
        import re
        
        if sys.platform == 'win32':
            # Windows: 解析 .lib
            md_lib_match = re.search(r'thostmduserapi[^\s]*\.lib', content)
            if md_lib_match:
                lib_name = md_lib_match.group().replace('.lib', '')
                libraries['md'] = lib_name
                print(f"找到行情库: {lib_name}")
            td_lib_match = re.search(r'thosttraderapi[^\s]*\.lib', content)
            if td_lib_match:
                lib_name = td_lib_match.group().replace('.lib', '')
                libraries['td'] = lib_name
                print(f"找到交易库: {lib_name}")
        else:
            # Unix/Linux/macOS: 解析 .so，去掉 lib 前缀
            print(f"解析Unix/Linux库文件...")
            md_so_match = re.search(r'(?:lib)?(thostmduserapi[^\s]*)\.so', content)
            if md_so_match:
                lib_name = md_so_match.group(1)
                libraries['md'] = lib_name
                print(f"找到行情库: {lib_name}")
            else:
                # 如果没有找到，尝试查找libthostmduserapi.so
                if 'libthostmduserapi.so' in content:
                    libraries['md'] = 'thostmduserapi'
                    print(f"使用默认行情库: thostmduserapi")
            
            td_so_match = re.search(r'(?:lib)?(thosttraderapi[^\s]*)\.so', content)
            if td_so_match:
                lib_name = td_so_match.group(1)
                libraries['td'] = lib_name
                print(f"找到交易库: {lib_name}")
            else:
                # 如果没有找到，尝试查找libthosttraderapi.so
                if 'libthosttraderapi.so' in content:
                    libraries['td'] = 'thosttraderapi'
                    print(f"使用默认交易库: thosttraderapi")
        
        print(f"最终库文件名: {libraries}")
        return libraries
    except Exception as e:
        print(f"解析.depend文件失败: {e}，使用默认库文件名")
        return libraries

def create_extensions():
    """创建扩展模块定义"""
    current_dir = get_current_dir()
    iconv_wrapper_path = os.path.join(current_dir, 'tools', 'iconv_wrapper.cpp')
    
    # 从.depend文件获取库文件名
    libraries = get_libraries_from_depend()
    
    extensions = []
    
    # 行情API扩展
    md_extension = Extension(
        '_thostmduserapi',
        sources=[
            'thostmduserapi_wrap.cxx',
            iconv_wrapper_path
        ],
        include_dirs=[
            current_dir,  # 当前目录
            os.path.join(current_dir, 'tools')  # tools目录
        ],
        libraries=[libraries['md']],
        library_dirs=[current_dir],
        language='c++'
    )
    extensions.append(md_extension)
    
    # 交易API扩展
    td_extension = Extension(
        '_thosttraderapi',
        sources=[
            'thosttraderapi_wrap.cxx',
            iconv_wrapper_path
        ],
        include_dirs=[
            current_dir,  # 当前目录
            os.path.join(current_dir, 'tools')  # tools目录
        ],
        libraries=[libraries['td']],
        library_dirs=[current_dir],
        language='c++'
    )
    extensions.append(td_extension)
    
    return extensions

def compile_extensions():
    """编译扩展模块"""
    try:
        print("开始编译扩展模块...")
        print(f"当前目录: {get_current_dir()}")
        print(f"Python 版本: {sys.version}")
        print(f"平台: {platform.system()} {platform.architecture()[0]}")
        
        extensions = create_extensions()
        
        # 设置编译参数
        setup(
            name='ctp-api',
            version='6.7.11',
            description='CTP API Python Bindings',
            ext_modules=extensions,
            cmdclass={'build_ext': CustomBuildExt},
            script_args=['build_ext', '--inplace']  # 在当前目录生成
        )
        
        print("编译完成！")
        
        # 检查生成的文件
        current_dir = get_current_dir()
        compiled = []
        for file in os.listdir(current_dir):
            if file.endswith('.pyd') or file.endswith('.so'):
                compiled.append(file)
        
        if compiled:
            print("生成的扩展文件:")
            for name in compiled:
                print(f"  - {name}")
        else:
            print("未找到生成的扩展文件(.pyd/.so)，请检查编译过程")
        
        return True
        
    except Exception as e:
        print(f"编译失败: {str(e)}")
        import traceback
        traceback.print_exc()
        return False

def main():
    """主函数"""
    print("CTP API Python 扩展简化编译脚本")
    print("=" * 50)
    
    # 检查文件
    if not check_files():
        print("文件检查失败，无法继续编译")
        sys.exit(1)
    
    # 编译扩展
    if not compile_extensions():
        print("\n编译失败！")
        sys.exit(1)
    
    print("\n编译成功！")
    print("生成的 .pyd 文件已保存在当前目录")
    
    # 获取项目类型
    project_type, _ = read_depend_file()
    package_name = f"py{project_type}"
    
    # 如果指定了目标目录，执行打包流程
    target_dir = package_name   # 使用 py[项目名] 作为目录名

    if target_dir:
        # 获取 py[项目名] 目录路径
        project_root = Path(__file__).parent.resolve()
        package_dir = project_root / target_dir

        # 检查目录是否存在
        if not os.path.exists(package_dir):
            os.makedirs(package_dir)

        print(f"\n开始打包流程，目标目录: {package_dir}")
        print(f"项目类型: {project_type}")
        print(f"包名: {package_name}")
        
        # 步骤1: 复制编译文件到指定目录的 py[项目名] 子目录
        print(f"\n步骤1: 复制编译文件到指定目录的 {package_name} 子目录...")
        if not copy_compiled_files(package_dir):
            print("❌ 打包失败！")
            sys.exit(1)
        


if __name__ == '__main__':
    main()